using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Web;
using System.Net;
using System.IO;
using System.Xml.Serialization;

namespace MyPhotoIndex.Plugins.Share.Flickr
{
    public class Flickr
    {
        private const string FlickrApiBaseAddress = "http://api.flickr.com/services/rest/";
        private const string FlickrApiAuthAddress = "http://www.flickr.com/services/auth/";
        private const string FlickrApiUploadAddress = "http://api.flickr.com/services/upload/";
     
        string m_apiKey;
		string m_sharedSecret;
		string m_apiToken;

        public event EventHandler<UploadProgressEventArgs> UploadProgress;

        public Flickr(string apiKey, string sharedSecret):
            this(apiKey, sharedSecret, null)
        {

        }

        public Flickr(string apiKey, string sharedSecret, string token)
        {
            m_apiKey = apiKey;
            m_sharedSecret = sharedSecret;
            m_apiToken = token;
        }

        public string AuthGetFrob()
        {
            HttpWebRequest webRequest = HttpWebRequest.Create(FlickrApiBaseAddress) as HttpWebRequest;
            RequestBuilder request = new RequestBuilder(m_apiKey, m_sharedSecret);
            request.InitializeRequest(webRequest, "flickr.auth.getFrob", String.Empty, false);

            String responseData = String.Empty;
            WebResponse response = webRequest.GetResponse();

            rsp frobRsp = null;
            using (Stream responseStream = response.GetResponseStream())
            {
                XmlSerializer serializer = new XmlSerializer(typeof(rsp));
                frobRsp = serializer.Deserialize(responseStream) as rsp;
            }

            return frobRsp.frob;
        }

        internal string AuthCalcUrl(string frob)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(m_sharedSecret);
            sb.Append("api_key" + m_apiKey);
            sb.Append("frob" + frob);
            sb.Append("perms" + "write");
			string hash = Md5Hash(sb.ToString());

            sb = new StringBuilder();
            sb.Append(FlickrApiAuthAddress);
            sb.Append("?api_key=" + m_apiKey);
            sb.Append("&perms=" + "write");
            sb.Append("&frob=" + frob);
            sb.Append("&api_sig=" + hash);

			string url =  sb.ToString();

			return url;
        }

        internal Auth AuthGetToken(string frob)
        {
            HttpWebRequest webRequest = HttpWebRequest.Create(FlickrApiBaseAddress) as HttpWebRequest;
            RequestBuilder request = new RequestBuilder(m_apiKey, m_sharedSecret);
            request.Add("frob", frob);
            request.InitializeRequest(webRequest, "flickr.auth.getToken", String.Empty, false);

            String responseData = String.Empty;
            WebResponse response = webRequest.GetResponse();

            rsp tokenRsp = null;
            using (Stream responseStream = response.GetResponseStream())
            {
                XmlSerializer serializer = new XmlSerializer(typeof(rsp));
                tokenRsp = serializer.Deserialize(responseStream) as rsp;
            }

            return new Auth(tokenRsp.auth.token);
        }

        internal string UploadPicture(string fileName, string title, string description, string tags, bool isPublic, bool isFamily, bool isFriend)
        {
            HttpWebRequest webRequest = HttpWebRequest.Create(FlickrApiUploadAddress) as HttpWebRequest;
            RequestBuilder request = new RequestBuilder(m_apiKey, m_sharedSecret);
            if (String.IsNullOrEmpty(title) == false)
            {
                request.Add("title", title);
            }

            if (String.IsNullOrEmpty(description) == false)
            {
                request.Add("description", description);
            }

            if (String.IsNullOrEmpty(tags) == false)
            {
                request.Add("tags", tags);
            }

            request.Add("is_public", isPublic ? "1" : "0");
            request.Add("is_friend", isFriend ? "1" : "0");
            request.Add("is_family", isFamily ? "1" : "0");

            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    request.BlobReadProgressEvent += new EventHandler<ProgressEventArgs>(request_BlobReadProgressEvent);
                    request.SetBlobParameter(title, fs, "image/jpeg");

                    request.InitializeRequest(webRequest, String.Empty, m_apiToken, true);

                    String responseData = String.Empty;
                    WebResponse response = webRequest.GetResponse();

                    rsp photoRsp = null;
                    using (Stream responseStream = response.GetResponseStream())
                    {
                        XmlSerializer serializer = new XmlSerializer(typeof(rsp));
                        photoRsp = serializer.Deserialize(responseStream) as rsp;
                    }

                    return photoRsp.photoid;
                }
                catch (Exception ex)
                {
                    MyPhotoIndex.Utilities.Logger.Log(ex);
                }
            }

            return String.Empty;
        }

        void request_BlobReadProgressEvent(object sender, ProgressEventArgs e)
        {
            if (UploadProgress != null)
            {
                UploadProgress.Invoke(this, new UploadProgressEventArgs(e.Value));
            }
        }

        private static string Md5Hash(string unhashed)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider csp = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(unhashed);
            byte[] hashedBytes = csp.ComputeHash(bytes, 0, bytes.Length);
            return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
        }
    }
}
